﻿/************************************************************************************
 * xujiajun@yoozoo.com 御剑
 * 层级容器，内部可以包含多个层级
 ***********************************************************************************/

using System.Collections.Generic;
using System.Text;
using Unity.Mathematics;

namespace WorldMapBase.Layer
{
    /// <summary>
    /// 层级容器，内部可以包含多个层级
    /// </summary>
    public class LayerContainer
    {
        /// <summary>
        /// 容器ID
        /// </summary>
        protected internal int id;

        /// <summary>
        /// 容器层级ID
        /// </summary>
        protected internal int layerId;

        /// <summary>
        /// 上一帧的视图尺寸
        /// </summary>
        private int4 m_LastViewRect;

        /// <summary>
        /// 当前容器策略
        /// </summary>
        private ILayerContainerStrategy m_Strategy;

        /// <summary>
        /// 待打开的层级数量
        /// </summary>
        private int m_ToEnableBufferCnt;

        /// <summary>
        /// 待关闭的层级数量
        /// </summary>
        private int m_ToDisableBufferCnt;

        /// <summary>
        /// 容器内所有层级的数量
        /// </summary>
        private int m_LayerCnt;

        /// <summary>
        /// 待打开的层级ID缓存
        /// </summary>
        private HashSet<int> m_ToEnableBuffer = new HashSet<int>();

        /// <summary>
        /// 待关闭的层级ID缓存
        /// </summary>
        private HashSet<int> m_ToDisableBuffer = new HashSet<int>();

        /// <summary>
        /// 容器内所有层级所在的列表
        /// </summary>
        private List<Layer> m_LayerList = new List<Layer>();

        /// <summary>
        /// 容器内所有层级和层级ID映射的集合（为了查找方便）
        /// </summary>
        private Dictionary<int, Layer> m_LayerDic = new Dictionary<int, Layer>();    

        public void Debug()
        {
            StringBuilder sb = new StringBuilder();
            foreach (var layer in m_LayerList)
            {
                sb.Append(layer.id);
                sb.Append(",");
            }
            UnityEngine.Debug.LogError(sb.ToString());
        }


        /// <summary>
        /// 设置容器策略
        /// </summary>
        /// <param name="strategy">容器策略</param>
        public void SetStrategy(ILayerContainerStrategy strategy)
        {
            m_Strategy = strategy;
        }

        /// <summary>
        /// 打开指定ID层级。会在下一帧执行该层级的创建
        /// </summary>
        /// <param name="id">层级ID</param>
        public void EnableLayer(int id)
        {
            if (m_ToEnableBuffer.Add(id))
            {
                m_ToDisableBuffer.Remove(id);
                m_ToEnableBufferCnt = m_ToEnableBuffer.Count;
                m_ToDisableBufferCnt = m_ToDisableBuffer.Count;
            }
        }

        /// <summary>
        /// 关闭指定ID层级。会在下一帧执行该层级的销毁
        /// </summary>
        /// <param name="id">层级ID</param>
        public void DisableLayer(int id)
        {
            if (m_ToDisableBuffer.Add(id))
            {
                m_ToEnableBuffer.Remove(id);
                m_ToEnableBufferCnt = m_ToEnableBuffer.Count;
                m_ToDisableBufferCnt = m_ToDisableBuffer.Count;
            }
        }

        /// <summary>
        /// 添加指定ID的层级。可以选择是否立即执行层级的创建。如果不立即执行创建，则需要在之后通过调用EnableLayer来进行创建
        /// </summary>
        /// <param name="id">层级ID</param>
        /// <param name="layer">层级对象</param>
        /// <param name="createImmediately">添加后的层级是否立即执行创建</param>
        /// <returns>层级是否添加成功</returns>
        public bool AddLayer(int layerID, int id, Layer layer, bool createImmediately = false)
        {
            if (!m_LayerDic.ContainsKey(id))
            {
                // 如果现有层级为0，或者层级ID不小于最后一位的ID，加到最后
                if (m_LayerCnt == 0 || m_Strategy.CompareLayer(id, m_LayerList[m_LayerCnt - 1].id) >= 0)
                {
                    m_LayerList.Add(layer);
                }
                // 如果层级ID小于第一位的ID，加到最前
                else if (m_Strategy.CompareLayer(id, m_LayerList[0].id) < 0)
                {
                    m_LayerList.Insert(0, layer);
                }
                // 其余使用两分法查找
                else
                {
                    var index = SearchInsertIndexBisection(id);
                    m_LayerList.Insert(index, layer);
                }
                m_LayerCnt++;
                m_LayerDic.Add(id, layer);

                layer.id = id;
                layer.layerID = layerID;
                if (createImmediately)
                {
                    layer.Create();
                    layer.forceUpdateViewRect = true;
                }
                return true;
            }
            else
            {
                UnityEngine.Debug.LogError(string.Format("添加层级失败，已存在id为{0}的层级", id));
                return false;
            }
        }

        /// <summary>
        /// 移除指定ID层级。移除的层级会立即执行销毁
        /// </summary>
        /// <param name="id">层级ID</param>
        /// <returns>层级是否移除成功</returns>
        public bool RemoveLayer(int id)
        {
            Layer layer;
            if (m_LayerDic.TryGetValue(id, out layer))
            {
                m_LayerDic.Remove(id);
                m_LayerList.Remove(layer);
                layer.Destroy();
                m_LayerCnt--;
                return true;
            }

            else
            {
                UnityEngine.Debug.LogError(string.Format("移除层级失败，不存在在id为{0}的层级", id));
            }
            return false;
        }


        /// <summary>
        /// 获取指定ID的层级
        /// </summary>
        /// <param name="id">层级ID</param>
        /// <returns>层级对象，如果没有获取到则为Null</returns>
        public Layer GetLayer(int id)
        {
            Layer layer;
            m_LayerDic.TryGetValue(id, out layer);
            return layer;
        }

        /// <summary>
        /// 清空容器内所有层级。所有的层级会被立即执行销毁
        /// </summary>
        public void Clear()
        {
            SetStrategy(null);
            for (int i = m_LayerCnt - 1; i >= 0; i--)
            {
                m_LayerList[i].Destroy();
            }
            m_LayerDic.Clear();
            m_LayerList.Clear();
            m_ToEnableBuffer.Clear();
            m_ToDisableBuffer.Clear();
            m_ToDisableBufferCnt = 0;
            m_ToEnableBufferCnt = 0;
            m_LayerCnt = 0;
        }

        /// <summary>
        /// 轮询更新
        /// </summary>
        internal void Update()
        {
            // 执行关闭子层级
            if (m_ToDisableBufferCnt > 0)
            {
                foreach (var key in m_ToDisableBuffer)
                {
                    Layer layer;
                    if (m_LayerDic.TryGetValue(key, out layer))
                    {
                        layer.Destroy();
                    }
                }
                m_ToDisableBufferCnt = 0;
                m_ToDisableBuffer.Clear();
            }

            // 执行打开子层级
            if (m_ToEnableBufferCnt > 0)
            {
                foreach (var key in m_ToEnableBuffer)
                {
                    Layer layer;
                    if (m_LayerDic.TryGetValue(key, out layer))
                    {
                        layer.Create();
                        layer.forceUpdateViewRect = true;
                    }
                }
                m_ToEnableBufferCnt = 0;
                m_ToEnableBuffer.Clear();
            }

            var viewRect = m_Strategy.GetViewRect();
            var result = m_LastViewRect == viewRect;
            var finalChange = !result.x || !result.y || !result.z || !result.w;
            // 视图发生变化时进行通知
            for (int i = 0; i < m_LayerCnt; i++)
            {
                var layer = m_LayerList[i];

                // 更新视图
                if (finalChange || layer.forceUpdateViewRect)
                {
                    //UnityEngine.Debug.LogError(string.Format("Layer视图更新 layercontainerID:{0},layerIndex:{1}",id,i));
                    
                    layer.UpdateViewRect(viewRect);
                    layer.forceUpdateViewRect = false;
                }
            }
            m_LastViewRect = viewRect;
            OnUpdate();
        }

        /// <summary>
        /// 轮询更新时响应
        /// </summary>
        protected virtual void OnUpdate()
        {

        }

        /// <summary>
        /// 两分法查找指定ID的层级可以插入到层级列表的位置
        /// </summary>
        /// <param name="targetID">待查找的层级ID</param>
        /// <returns>可以插入到层级列表的位置</returns>
        private int SearchInsertIndexBisection(int targetID)
        {
            var leftIndex = 0;                      // 最左的序号
            var rightIndex = m_LayerCnt - 1;        // 最右的序号
            var searchIndex = m_LayerCnt >> 1;      // 位于中间的序号
            while (rightIndex - leftIndex > 1)
            {
                var result = m_Strategy.CompareLayer(targetID, m_LayerList[searchIndex].id);
                if (result < 0)
                {
                    rightIndex = searchIndex;
                }
                else
                {
                    leftIndex = searchIndex;
                }
                searchIndex = ((rightIndex - leftIndex) >> 1) + leftIndex;
            }
            return rightIndex;
        }

        public int4 ViewRect => m_LastViewRect;
    }

}
